Data reading

hogwarts <- read_csv("data/hogwarts_2024.csv")
hogwarts |> head()
## # A tibble: 6 × 60
##      id house    course sex   wandCore bloodStatus result Defence against the …¹
##   <dbl> <chr>     <dbl> <chr> <chr>    <chr>        <dbl>                  <dbl>
## 1     1 Ravencl…      4 fema… unicorn… half-blood      94                     73
## 2     2 Hufflep…      5 male  phoenix… half-blood      33                     38
## 3     3 Ravencl…      4 fema… dragon … half-blood     137                     52
## 4     4 Hufflep…      2 male  phoenix… half-blood      27                     50
## 5     5 Hufflep…      2 fema… phoenix… half-blood      67                     47
## 6     6 Gryffin…      6 male  phoenix… muggle-born    126                     44
## # ℹ abbreviated name: ¹​`Defence against the dark arts exam`
## # ℹ 52 more variables: `Flying exam` <dbl>, `Astronomy exam` <dbl>,
## #   `Herbology exam` <dbl>, `Divinations exam` <dbl>, `Charms exam` <dbl>,
## #   `History of magic exam` <dbl>, `Arithmancy exam` <dbl>,
## #   `Care of magical creatures exam` <dbl>, `Muggle studies exam` <dbl>,
## #   `Study of ancient runes exam` <dbl>, `Transfiguration exam` <dbl>,
## #   `Potions exam` <dbl>, week_1 <dbl>, week_2 <dbl>, week_3 <dbl>, …

Checking dataset structure

hogwarts |> glimpse()
## Rows: 560
## Columns: 60
## $ id                                   <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11…
## $ house                                <chr> "Ravenclaw", "Hufflepuff", "Raven…
## $ course                               <dbl> 4, 5, 4, 2, 2, 6, 7, 5, 2, 3, 7, …
## $ sex                                  <chr> "female", "male", "female", "male…
## $ wandCore                             <chr> "unicorn hair", "phoenix feather"…
## $ bloodStatus                          <chr> "half-blood", "half-blood", "half…
## $ result                               <dbl> 94, 33, 137, 27, 67, 126, 63, 7, …
## $ `Defence against the dark arts exam` <dbl> 73, 38, 52, 50, 47, 44, 51, 47, 2…
## $ `Flying exam`                        <dbl> 33, 36, 73, 42, 41, 52, 34, 34, 2…
## $ `Astronomy exam`                     <dbl> 57, 45, 66, 49, 57, 59, 58, 37, 5…
## $ `Herbology exam`                     <dbl> 73, 50, 62, 39, 38, 46, 59, 23, 2…
## $ `Divinations exam`                   <dbl> 66, 54, 72, 42, 47, 49, 42, 38, 1…
## $ `Charms exam`                        <dbl> 60, 70, 77, 46, 35, 55, 86, 20, 4…
## $ `History of magic exam`              <dbl> 52, 36, 60, 45, 50, 40, 55, 21, 2…
## $ `Arithmancy exam`                    <dbl> 61, 36, 58, 32, 76, 50, 41, 31, 2…
## $ `Care of magical creatures exam`     <dbl> 44, 41, 70, 36, 46, 73, 29, 36, 4…
## $ `Muggle studies exam`                <dbl> 64, 34, 52, 59, 50, 54, 36, 31, 4…
## $ `Study of ancient runes exam`        <dbl> 50, 35, 59, 39, 48, 56, 47, 41, 3…
## $ `Transfiguration exam`               <dbl> 74, 70, 70, 15, 32, 86, 100, 31, …
## $ `Potions exam`                       <dbl> 67, 38, 22, 64, 56, 60, 62, 55, 1…
## $ week_1                               <dbl> 0, -5, 0, -1, 1, 5, 1, -20, 3, -2…
## $ week_2                               <dbl> -10, 1, 0, 5, 20, 10, -5, 10, 1, …
## $ week_3                               <dbl> 0, -1, 1, -5, 10, -5, 3, -5, -3, …
## $ week_4                               <dbl> 10, 1, -1, 10, -10, 10, 0, -10, -…
## $ week_5                               <dbl> 3, -5, 3, 0, -1, 20, 5, 5, -3, 5,…
## $ week_6                               <dbl> -20, 20, 0, 0, 0, 0, 0, 5, 0, -1,…
## $ week_7                               <dbl> 10, 10, 1, -3, -20, 1, 10, 3, -5,…
## $ week_8                               <dbl> 5, 5, 1, -5, 5, 5, 0, 1, 0, 20, -…
## $ week_9                               <dbl> 1, 1, 3, -1, 0, 3, -20, -20, -10,…
## $ week_10                              <dbl> 20, -10, 1, 5, -1, 0, 5, -5, 5, 3…
## $ week_11                              <dbl> 5, -10, 20, 0, 0, 0, 5, 10, 5, 5,…
## $ week_12                              <dbl> 5, -5, 1, -20, -10, -5, 0, 5, 1, …
## $ week_13                              <dbl> -20, -5, 10, 0, 0, 1, -1, 10, -20…
## $ week_14                              <dbl> 0, 5, 3, 10, -10, 20, 0, -20, -20…
## $ week_15                              <dbl> 1, 20, 1, 0, -20, 10, 1, 3, -20, …
## $ week_16                              <dbl> 20, 5, 5, 5, 0, 3, 10, -1, 5, 5, …
## $ week_17                              <dbl> 3, 0, 10, 5, 5, -5, -1, 10, -10, …
## $ week_18                              <dbl> 10, 5, 5, 5, 10, -20, 0, 10, 3, 5…
## $ week_19                              <dbl> -10, 0, -5, -1, 0, -1, 0, 20, 0, …
## $ week_20                              <dbl> 10, -10, 5, 10, 0, -1, -1, 10, 0,…
## $ week_21                              <dbl> 0, 5, 5, 3, 5, 0, 0, -5, -5, 5, 5…
## $ week_22                              <dbl> 20, -5, 5, 0, 20, 5, -1, 0, 0, 20…
## $ week_23                              <dbl> 5, 1, -3, 20, -5, 20, 0, 1, 1, 5,…
## $ week_24                              <dbl> 10, -20, -20, 0, 10, 5, 5, -3, -5…
## $ week_25                              <dbl> 0, -20, 1, 3, 5, 1, -5, 0, -20, 2…
## $ week_26                              <dbl> 10, 10, 5, -1, 0, 5, 5, -3, 0, 20…
## $ week_27                              <dbl> 5, 5, -3, 0, 20, 5, 0, -5, 10, 3,…
## $ week_28                              <dbl> -3, 20, 20, 1, 10, 5, 1, 10, 0, 1…
## $ week_29                              <dbl> -20, -5, 5, 5, -10, 1, 0, -3, 0, …
## $ week_30                              <dbl> 5, 1, -5, 5, -5, -1, -20, 20, 1, …
## $ week_31                              <dbl> 5, 5, 20, -5, -10, -3, 0, -10, 20…
## $ week_32                              <dbl> -5, 1, 20, -1, -10, 5, 10, 1, 0, …
## $ week_33                              <dbl> 0, 10, 3, 3, 0, 0, -1, 0, -20, 3,…
## $ week_34                              <dbl> 0, -1, 0, 0, 10, 3, 20, -5, 10, 3…
## $ week_35                              <dbl> 5, -5, 3, -10, 3, -5, 0, 0, 0, 0,…
## $ week_36                              <dbl> 1, 5, 1, -20, 5, 20, -1, -3, 1, 3…
## $ week_37                              <dbl> 0, 0, 10, -1, 10, 3, 3, 0, 20, 1,…
## $ week_38                              <dbl> 10, -1, 0, -5, 5, 5, 20, -5, -3, …
## $ week_39                              <dbl> 3, 5, 1, 10, 20, 0, 5, 1, -5, 0, …
## $ week_40                              <dbl> 0, 0, 5, 1, 5, 1, 10, -5, -20, 3,…
# Changing some variables type to factors
hogwarts <- hogwarts |> mutate(
  across(c(house, course, sex, wandCore, bloodStatus), ~ as.factor(.x))
)

NA checking

sum(is.na(hogwarts))
## [1] 0

Summary output

hogwarts |> summary()
##        id               house     course      sex                    wandCore  
##  Min.   :  1.0   Gryffindor:126   1: 80   female:333   dragon heartstring:196  
##  1st Qu.:140.8   Hufflepuff:179   2:101   male  :227   phoenix feather   :181  
##  Median :280.5   Ravenclaw :122   3: 67                unicorn hair      :183  
##  Mean   :280.5   Slytherin :133   4: 71                                        
##  3rd Qu.:420.2                    5: 88                                        
##  Max.   :560.0                    6: 67                                        
##                                   7: 86                                        
##       bloodStatus      result        Defence against the dark arts exam
##  half-blood :391   Min.   :-292.00   Min.   : 0                        
##  muggle-born: 60   1st Qu.:   7.00   1st Qu.:39                        
##  pure-blood :109   Median :  70.50   Median :49                        
##                    Mean   :  59.71   Mean   :48                        
##                    3rd Qu.: 128.25   3rd Qu.:58                        
##                    Max.   : 260.00   Max.   :89                        
##                                                                        
##   Flying exam    Astronomy exam  Herbology exam  Divinations exam
##  Min.   : 0.00   Min.   : 0.00   Min.   : 0.00   Min.   : 0.00   
##  1st Qu.:36.00   1st Qu.:37.00   1st Qu.:39.00   1st Qu.:38.00   
##  Median :48.00   Median :49.00   Median :49.00   Median :49.00   
##  Mean   :47.37   Mean   :47.99   Mean   :47.75   Mean   :48.44   
##  3rd Qu.:60.00   3rd Qu.:60.00   3rd Qu.:58.00   3rd Qu.:59.00   
##  Max.   :85.00   Max.   :87.00   Max.   :86.00   Max.   :89.00   
##                                                                  
##   Charms exam    History of magic exam Arithmancy exam
##  Min.   : 0.00   Min.   : 0.00         Min.   : 0.00  
##  1st Qu.:39.00   1st Qu.:37.00         1st Qu.:38.00  
##  Median :49.00   Median :48.00         Median :50.00  
##  Mean   :48.36   Mean   :47.28         Mean   :48.38  
##  3rd Qu.:59.00   3rd Qu.:58.00         3rd Qu.:60.00  
##  Max.   :98.00   Max.   :85.00         Max.   :91.00  
##                                                       
##  Care of magical creatures exam Muggle studies exam Study of ancient runes exam
##  Min.   : 0.00                  Min.   : 0.00       Min.   : 0.00              
##  1st Qu.:38.00                  1st Qu.:38.00       1st Qu.:38.00              
##  Median :49.00                  Median :50.00       Median :48.00              
##  Mean   :48.11                  Mean   :48.64       Mean   :47.44              
##  3rd Qu.:60.00                  3rd Qu.:61.00       3rd Qu.:58.00              
##  Max.   :95.00                  Max.   :94.00       Max.   :89.00              
##                                                                                
##  Transfiguration exam  Potions exam        week_1            week_2       
##  Min.   :  0.00       Min.   :  0.00   Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: 34.00       1st Qu.: 21.00   1st Qu.: -3.000   1st Qu.: -3.000  
##  Median : 49.00       Median : 47.00   Median :  1.000   Median :  1.000  
##  Mean   : 48.24       Mean   : 46.62   Mean   :  1.334   Mean   :  1.161  
##  3rd Qu.: 62.25       3rd Qu.: 68.00   3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   :100.00       Max.   :100.00   Max.   : 50.000   Max.   : 20.000  
##                                                                           
##      week_3            week_4           week_5             week_6       
##  Min.   :-20.000   Min.   :-20.00   Min.   :-20.0000   Min.   :-20.000  
##  1st Qu.: -1.500   1st Qu.: -1.00   1st Qu.: -3.0000   1st Qu.: -1.000  
##  Median :  1.000   Median :  1.00   Median :  1.0000   Median :  1.000  
##  Mean   :  1.407   Mean   :  1.82   Mean   :  0.9196   Mean   :  1.448  
##  3rd Qu.:  5.000   3rd Qu.:  5.00   3rd Qu.:  5.0000   3rd Qu.:  5.000  
##  Max.   : 20.000   Max.   : 20.00   Max.   : 20.0000   Max.   : 20.000  
##                                                                         
##      week_7            week_8          week_9          week_10       
##  Min.   :-20.000   Min.   :-20.0   Min.   :-50.00   Min.   :-20.000  
##  1st Qu.: -3.000   1st Qu.: -1.0   1st Qu.: -1.00   1st Qu.: -1.000  
##  Median :  1.000   Median :  1.0   Median :  1.00   Median :  1.000  
##  Mean   :  1.529   Mean   :  1.6   Mean   :  1.63   Mean   :  1.457  
##  3rd Qu.:  5.000   3rd Qu.:  5.0   3rd Qu.:  5.00   3rd Qu.:  5.000  
##  Max.   : 20.000   Max.   : 20.0   Max.   : 20.00   Max.   : 20.000  
##                                                                      
##     week_11           week_12           week_13            week_14      
##  Min.   :-20.000   Min.   :-20.000   Min.   :-20.0000   Min.   :-20.00  
##  1st Qu.: -1.000   1st Qu.: -1.000   1st Qu.: -3.0000   1st Qu.: -1.00  
##  Median :  1.000   Median :  1.000   Median :  0.0000   Median :  1.00  
##  Mean   :  1.586   Mean   :  1.689   Mean   :  0.7393   Mean   :  1.53  
##  3rd Qu.:  5.000   3rd Qu.:  5.000   3rd Qu.:  5.0000   3rd Qu.:  5.00  
##  Max.   : 20.000   Max.   : 20.000   Max.   : 50.0000   Max.   : 20.00  
##                                                                         
##     week_15           week_16           week_17         week_18       
##  Min.   :-20.000   Min.   :-20.000   Min.   :-20.0   Min.   :-20.000  
##  1st Qu.: -1.000   1st Qu.: -1.000   1st Qu.: -1.0   1st Qu.: -1.000  
##  Median :  1.000   Median :  1.000   Median :  1.0   Median :  1.000  
##  Mean   :  1.738   Mean   :  1.636   Mean   :  1.8   Mean   :  1.712  
##  3rd Qu.:  5.000   3rd Qu.:  5.000   3rd Qu.:  5.0   3rd Qu.:  5.000  
##  Max.   : 20.000   Max.   : 20.000   Max.   : 50.0   Max.   : 20.000  
##                                                                       
##     week_19            week_20          week_21           week_22       
##  Min.   :-50.0000   Min.   :-20.00   Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: -3.0000   1st Qu.: -3.00   1st Qu.: -1.000   1st Qu.: -1.000  
##  Median :  0.0000   Median :  1.00   Median :  1.000   Median :  1.000  
##  Mean   :  0.8071   Mean   :  1.55   Mean   :  1.816   Mean   :  1.527  
##  3rd Qu.:  5.0000   3rd Qu.:  5.00   3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   : 20.0000   Max.   : 50.00   Max.   : 20.000   Max.   : 20.000  
##                                                                         
##     week_23            week_24           week_25           week_26       
##  Min.   :-20.0000   Min.   :-20.000   Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: -3.0000   1st Qu.: -1.000   1st Qu.: -3.000   1st Qu.: -3.000  
##  Median :  0.0000   Median :  1.000   Median :  1.000   Median :  1.000  
##  Mean   :  0.8036   Mean   :  1.168   Mean   :  1.364   Mean   :  1.248  
##  3rd Qu.:  5.0000   3rd Qu.:  5.000   3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   : 20.0000   Max.   : 20.000   Max.   : 20.000   Max.   : 20.000  
##                                                                          
##     week_27         week_28           week_29           week_30       
##  Min.   :-50.0   Min.   :-20.000   Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: -1.0   1st Qu.: -1.500   1st Qu.: -1.000   1st Qu.: -1.000  
##  Median :  1.0   Median :  1.000   Median :  0.000   Median :  1.000  
##  Mean   :  1.5   Mean   :  1.923   Mean   :  1.262   Mean   :  1.705  
##  3rd Qu.:  5.0   3rd Qu.:  5.000   3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   : 20.0   Max.   : 20.000   Max.   : 20.000   Max.   : 20.000  
##                                                                       
##     week_31          week_32           week_33           week_34       
##  Min.   :-20.00   Min.   :-20.000   Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: -1.00   1st Qu.: -1.000   1st Qu.: -1.000   1st Qu.: -1.000  
##  Median :  1.00   Median :  1.000   Median :  1.000   Median :  1.000  
##  Mean   :  1.68   Mean   :  2.013   Mean   :  1.539   Mean   :  1.593  
##  3rd Qu.:  5.00   3rd Qu.:  5.000   3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   : 20.00   Max.   : 20.000   Max.   : 20.000   Max.   : 20.000  
##                                                                        
##     week_35         week_36           week_37          week_38       
##  Min.   :-20.0   Min.   :-20.000   Min.   :-20.00   Min.   :-20.000  
##  1st Qu.: -1.0   1st Qu.: -1.000   1st Qu.: -1.00   1st Qu.: -1.000  
##  Median :  1.0   Median :  1.000   Median :  1.00   Median :  1.000  
##  Mean   :  1.7   Mean   :  2.079   Mean   :  1.32   Mean   :  1.864  
##  3rd Qu.:  5.0   3rd Qu.:  5.000   3rd Qu.:  5.00   3rd Qu.:  5.000  
##  Max.   : 20.0   Max.   : 20.000   Max.   : 20.00   Max.   : 20.000  
##                                                                      
##     week_39           week_40       
##  Min.   :-20.000   Min.   :-20.000  
##  1st Qu.: -1.000   1st Qu.: -3.000  
##  Median :  1.000   Median :  0.000  
##  Mean   :  1.438   Mean   :  1.079  
##  3rd Qu.:  5.000   3rd Qu.:  5.000  
##  Max.   : 20.000   Max.   : 20.000  
## 

Data visualisation

1 фактор

Торт Наполеон
Торт Наполеон
ggplot(hogwarts)+
  geom_bar(aes(x = house))+ 
  theme_bw()

  # coord_
  # scale_
  # facet_

Цвета

Покрасим столбцы в отличный от серого цвет.

ggplot(hogwarts)+
  geom_bar(aes(x = house), 
           colour = "red", 
           fill = "green")+ 
  theme_bw()

Раскрасим факультеты в разные цвета.

ggplot(hogwarts)+
  geom_bar(aes(x = house, fill = house), colour = "black")+ 
  theme_bw()

Выделим один факультет цветом.

ggplot()+
  geom_bar(data = hogwarts, aes(x = house, fill = (house == "Ravenclaw")), 
           colour = "black")+ 
  theme_bw()

Покрасим факультеты в правильные цвета.

ggplot(hogwarts)+
  geom_bar(aes(x = house, 
               fill = house), 
           colour = "black")+ 
  scale_fill_manual(values = c("Gryffindor" = "#C50000", 
                               "Hufflepuff" = "#ECB939", 
                               "Ravenclaw" = "#41A6D9", 
                               "Slytherin" = "#1F5D25"))+
  theme_bw()

Резюме

  1. ggplot составляют 5 основных компонентов: геомы, оси, фасеты, координатная плоскость и тема
  2. Внутри геомов есть эстетики. Внутрь эстетик мы помещаем те переменные из данных, которые желаем видеть на графике. Это будут наши оси.
  3. Ось – не только координата x и y – любая эстетика, например, заливка, тоже может быть осью.
  4. Цвет в ggplot можно задать как словесно, так и при помощи гекскода.
  5. У цвета есть три основных применения – различение групп, акцентирование подмножества объектов, отражение свойства, связанного с цветом.
  6. Можно подробно настроить оси при помощи опции scale (основные типы функций, которые пригождаются – discrete, continuous и manual).
  7. Распределение 1-й категориальной/факторной/качественной/номинативной переменной можно представить в виде столбиковой диаграммы (барплота).

2 фактора

Добавим второй фактор.

ggplot(hogwarts)+
  geom_bar(aes(x = fct_infreq(house), 
               fill = sex), 
           colour = "black", 
           position = "dodge2")+ 
  scale_x_discrete(name = "house")+
  theme_bw()

theme_custom <- theme(
    axis.text = element_text(size = 20),
    axis.title = element_text(size = 25),
    # axis.text.x = element_text(angle = 15),
    legend.title = element_text(size = 20),
    legend.text = element_text(size = 20)
  )

bar_custom <- geom_bar(aes(y = fct_infreq(house), 
                           fill = sex), 
                       colour = "black", 
                       position = "dodge2")

bar_plot_def <- ggplot(hogwarts)+
  bar_custom+
  scale_y_discrete(name = "house")+
  theme_bw()+
  theme_custom

bar_plot_def

Резюме.

1. У geom_bar есть аргумент position, который позволяет манипулировать взаиморасположением второй факторной переменной. Опция dodge/dodge2 ставит столбики подгрупп внутри группы рядом, а опция fill укладывает их друг на друга в отшкалированном виде.

2. Функции из семейства forcats (fct_reorder(), fct_infreq() и другие) позволяют менять порядок факторных переменных.

3. Функция theme() позволяет тонко регулировать различные оформительские аспекты графика. Например, размер и угол наклона шрифта.

4. Элементы ggplot можно сохранять в переменные и переиспользовать.

1 качественная переменная с большим числом градаций

hogwarts |> 
  filter(id  %in% 1:40) |> 
  mutate(id = as.factor(id)) |> 
  ggplot()+
  geom_segment(aes(x = fct_reorder(id, week_1), 
                   xend = fct_reorder(id, week_1), 
                   y = 0, 
                   yend = week_1))+
  geom_point(aes(x = fct_reorder(id, week_1), 
                 y = week_1), 
             colour = "red", 
             size = 3)+
  geom_hline(yintercept = 7, 
             linetype = "dashed", 
             linewidth = 2, 
             colour = "#218379")+
  labs(x = "id",
       title = "Пример 'леденцового' графика",
       subtitle = "подзаголовок графика",
       caption = "Писано мною осенью 2024-го года")+
  theme_bw()+
  theme_custom+
  theme(
    plot.title = element_text(size = 20, hjust = 0.5),
    plot.subtitle = element_text(size = 15, hjust = 0.5)
  )

Временные тренды

Отследим, как студент приносил или отнимал баллы у факультета

# Создадим новый субдатасет
students10ForWeeks <- hogwarts |> 
  select(id, starts_with("week")) |> 
  pivot_longer(!id, names_to = "week", values_to = "points") |> 
  filter(id  %in%  1:10) |> 
  mutate(
    week = week |> str_split_i("_", 2) |> as.numeric()
    )

# Отрисуем график
ggplot()+
  geom_line(data = students10ForWeeks, 
            aes(x = week, 
                y = points, 
                group = id))+
  theme_bw()+
  theme_custom

“Подсветим” конкретного студента

ggplot()+
  geom_line(data = students10ForWeeks, 
            aes(x = week, 
                y = points, 
                group = id), 
            colour = "grey")+
  geom_line(data = students10ForWeeks |> filter(id == 10), 
            aes(x = week, 
                y = points))+
  theme_bw()+
  theme_custom

Резюме:

1. Для категориальных переменных с большим числом категорий можно заменить барплот лоллипопом.

2. На графики можно добавлять графические примитивы – линии и фигуры, которые создают смысловой акцент, показывают отсечку и т.д.

3. Изменения во времени хорошо передают лайнплоты.

4. Если на лайнплоте слишком много линий, есть два хороших решения: убрать график или сделать акцентными нужные единицы наблюдения, убрав в тень остальные.

1 количественная переменная

ggplot(hogwarts)+
  geom_bar(aes(x = result))+
  theme_bw()+
  theme_custom

Иной подход к визуализации количественной переменной

ggplot(hogwarts)+
  geom_histogram(aes(x = `Potions exam`), 
                 fill = "turquoise1", 
                 colour = "grey49", 
                 bins = ceiling(log2(nrow(hogwarts))+1))+
  theme_bw()+
  theme_custom

И еще один.

ggplot(hogwarts)+
  geom_density(aes(x = `Potions exam`), 
               fill = "turquoise1", 
               colour = "grey49", 
               bins = ceiling(log2(nrow(hogwarts))+1))+
  theme_bw()+
  theme_custom

Малое количество наблюдений

hogwarts |> 
  filter(course == 7, house == "Ravenclaw") |> 
  ggplot()+
  geom_density(aes(x = `Potions exam`), 
               fill = "turquoise1", 
               colour = "grey49", 
               bins = ceiling(log2(nrow(hogwarts))+1))+
  theme_bw()+
  theme_custom

Сравнение нескольких количественных переменных

ggplot(hogwarts)+
  geom_density(aes(x = `Potions exam`), 
               fill = "lightgreen", 
               colour = "grey49", 
               alpha = 0.5, 
               bins = ceiling(log2(nrow(hogwarts))+1))+
  geom_density(aes(x = `Charms exam`), 
               fill = "turquoise1", 
               colour = "grey49", 
               alpha = 0.5, 
               bins = ceiling(log2(nrow(hogwarts))+1))+
  geom_density(aes(x = `Transfiguration exam`), 
               fill = "red4", 
               colour = "grey49", 
               alpha = 0.5, 
               bins = ceiling(log2(nrow(hogwarts))+1))+
  theme_bw()+
  theme_custom

Резюме.

1. У geom_bar есть аргумент position, который позволяет манипулировать взаиморасположением второй факторной переменной. Опция dodge/dodge2 ставит столбики подгрупп внутри группы рядом, а опция fill укладывает их друг на друга в отшкалированном виде.

2. Функции из семейства forcats (например, fct_infreq()) позволяют менять порядок факторных переменных.

3. Функция theme() позволяет тонко регулировать различные оформительские аспекты графика. Например, размер и угол наклона шрифта.

4. Элементы ggplot можно сохранять в переменные и переиспользовать.

1 количественная переменная и фактор

Сравним несколько распределений

ggplot(hogwarts)+
  geom_boxplot(aes(y = `Potions exam`, 
                   x = house), 
               colour = "grey49")+
  theme_bw()+
  theme_custom

Сравним несколько переменных

hogwarts |> 
  select(id, `Transfiguration exam`, `Potions exam`, `Defence against the dark arts exam`) |> 
  pivot_longer(!id, 
               names_to = "exam", 
               values_to = "score") |> 
  ggplot()+
  geom_boxplot(aes(x = exam, 
                   y = score))+
  theme_bw()+
  theme_custom

В чем плюсы и минусы двух этих представлений количественных переменных?

hogwarts |> 
  ggplot(aes(x = result))+
  geom_boxplot(fill = "lightgreen", 
               alpha = 0.5, 
               width = 30, 
               linewidth = 2, 
               outlier.size = 2)+
  geom_histogram(fill = "lightblue", 
                 alpha = 0.5, 
                 colour = 20, 
                 bins = 20)+
  theme_bw()+
  theme_custom

А есть ли что-то, сочетающее их свойства?

hogwarts |> 
  filter(house == "Slytherin") |> 
  select(id, `Transfiguration exam`, `Potions exam`, `Defence against the dark arts exam`) |> 
  pivot_longer(!id, names_to = "exam", values_to = "score") |> 
  ggplot()+
  geom_jitter(aes(x = exam, y = score))+
  theme_bw()+
  theme_custom

Комбинируем разные слои, смотрим справку

hogwarts |> 
  filter(house == "Slytherin") |> 
  select(id, `Transfiguration exam`, `Potions exam`, `Defence against the dark arts exam`) |> 
  pivot_longer(!id, names_to = "exam", values_to = "score") |> 
  ggplot(aes(x = exam, y = score))+
  geom_boxplot(notch = TRUE)+
  geom_jitter()+
  theme_bw()+
  theme_custom

1 количественная и 2 факторные переменные

hogwarts |> 
  filter(house == "Slytherin") |> 
  select(id, `Transfiguration exam`, `Potions exam`, `Defence against the dark arts exam`, sex) |> 
  pivot_longer(-c(id, sex), names_to = "exam", values_to = "score") |> 
  ggplot(aes(x = exam, y = score, fill = sex))+
  geom_boxplot(notch = TRUE, outliers = FALSE)+
  geom_jitter()+
  theme_bw()+
  theme_custom

hogwarts |> 
  filter(house == "Slytherin") |> 
  select(id, `Transfiguration exam`, `Potions exam`, `Defence against the dark arts exam`, sex, wandCore) |> 
  pivot_longer(-c(id, sex, wandCore), names_to = "exam", values_to = "score") |> 
  ggplot(aes(x = exam, y = score, fill = sex, alpha = wandCore))+
  geom_boxplot(notch = TRUE, outliers = FALSE)+
  geom_jitter()+
  theme_bw()+
  theme_custom

Резюме:

1. Распределение количественной переменной можно представить в виде боксплота. На боксплоте мы видим несколько простых статистик (квартили, межквартильный размах) и выбросы, но не видим деталей распределения.

2. Преодоелние предыдущей проблемы боксплота – jitter и violin. Первый хорош для наборов данных с малым числом наблюдений, второй – с большим.

3. На одном графике можно сочетать не только геомы одного типа, но и разные. Например, сделать боксплот с джиттером.

4. Справка по конкретным функциям позволяет узнать о разных опциях и настройках: например, на боксплоте мы можем убрать выбросы или добавить вырезку.

5. Боксплоты, как и барплоты, можно разбивать по категориям.

Еще один способ сравнить распределения по группам

ggplot(hogwarts)+
  geom_histogram(aes(x = `Potions exam`), 
                 fill = "turquoise1", 
                 colour = "grey49", 
                 bins = 20)+
  facet_grid(wandCore~sex)+
  theme_bw()+
  theme_custom+
  theme(
    strip.text = element_text(size = 20)
  )

ggplot(hogwarts)+
  geom_boxplot(aes(y = `Potions exam`), 
                 fill = "turquoise1", 
                 colour = "grey49", 
                 bins = 20)+
  facet_grid(.~house)+
  theme_bw()+
  theme_custom

И немного другой подход

ggplot(hogwarts)+
  geom_histogram(aes(x = `Potions exam`), 
                 fill = "turquoise1", 
                 colour = "grey49", 
                 bins = 20)+
  facet_wrap(vars(course))+
  theme_bw()+
  theme_custom+
  theme(strip.text = element_text(size = 15))

Распределение 2-х количественных переменных

hogwarts |> 
  ggplot()+
  geom_histogram(aes(x = `Charms exam`),
                 colour = "black", 
                 fill = "lightgreen")+
  geom_histogram(aes(y = `Transfiguration exam`),
                 colour = "black", 
                 fill = "lightgreen")+
  theme_bw()+
  theme_custom

hogwarts |> 
  ggplot()+
  geom_point(aes(x = `Charms exam`, 
                 y = `Transfiguration exam`))+
  theme_bw()+
  theme_custom

hogwarts |> 
  ggplot()+
  geom_point(aes(x = `Charms exam`, 
                 y = `Transfiguration exam`), 
             shape = 23, 
             size = 3, 
             stroke = 2, 
             fill = "red")+
  theme_bw()+
  theme_custom

hogwarts |> 
  mutate(course = as.factor(course)) |> 
  ggplot()+
  geom_point(aes(x = `Charms exam`, 
                 y = `Transfiguration exam`, 
                 shape = course, 
                 colour = course), 
             size = 3)+
  scale_shape_manual(values = c("1" = 49, "2" = 50, "3" = 51, "4" = 52, "5" = 53, "6" = 54, "7" = 55))+
  theme_bw()+
  theme_custom

hogwarts |> 
  mutate(course = as.factor(course)) |> 
  ggplot()+
  geom_point(aes(x = `Charms exam`, y = `Transfiguration exam`, shape = course, colour = course), size = 3,
             position = position_jitter(width = 2, height = 2))+
  scale_shape_manual(values = c("1" = 49, "2" = 50, "3" = 51, "4" = 52, "5" = 53, "6" = 54, "7" = 55))+
  theme_bw()+
  theme_custom+
  annotate("text", x = 50, y = 50, label = "To be continue...", size = 40)

Резюме:

1. Стандартный инструмент для визуализации двух количественных переменных – диаграмма рассеяния.

2. Если необходимо добавить на график еще 1 факторный признак – выделяем его цветом.

3. Размер не лучшая опция для использования “в соло”, но может добавить выразительности в сочетании с цветом.

4. При большой кучности точек в определенных позициях полезно использовать jitter для случайного перемешивания.

5. Аннотации помогают подсветить важную деталь в данных. Или намекнуть, что лекция подошла к концу.

Ссылочная